package main

import (
	"encoding/json"
	"fmt"
	"strconv"
	// "strings"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

type StorageChaincode struct {
}

func (t *StorageChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

func (t *StorageChaincode) PutState(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting key and value")
	}

	timestemp := strconv.FormatInt(time.Now().Unix(), 10)
	err := stub.PutState(args[0], []byte(timestemp+args[1]))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

//getState
func (t *StorageChaincode) GetState(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting key")
	}

	value, err := stub.GetState(args[0])
	if err != nil {
		return shim.Error(err.Error())
	}

	if len(value) == 0 {
		return shim.Error("State Not Found")
	}
	return shim.Success(value)
}

func (t *StorageChaincode) GetStateByRange(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting startKey and endKey ")
	}

	resultsIterator, err := stub.GetStateByRange(args[0], args[1])
	if err != nil {
		return shim.Error(err.Error())
	}
	defer resultsIterator.Close()

	states := make([][]string, 0, 10)
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		states = append(states, []string{
			queryResponse.Key,
			string(queryResponse.Value),
		})

	}
	data, _ := json.Marshal(states)

	return shim.Success(data)
}

func (t *StorageChaincode) GetStateByPrefix(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting  Prefix")
	}

	endKey := []byte(args[0])
	endKey[len(endKey)-1] = endKey[len(endKey)-1] + 1
	args = append(args, string(endKey))
	return t.GetStateByRange(stub, args)
}

func (t *StorageChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	switch function {
	case "PutState":
		return t.PutState(stub, args)
	case "GetState":
		return t.GetState(stub, args)
	case "GetStateByRange":
		return t.GetStateByRange(stub, args)
	case "GetStateByPrefix":
		return t.GetStateByPrefix(stub, args)
	}

	return shim.Error("Invalid invoke function name " + function)
}

func main() {
	err := shim.Start(new(StorageChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
